/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.meta.service.impl;

import com.google.common.base.Strings;
import com.je.common.base.DynaBean;
import com.je.common.base.mapper.query.NativeQuery;
import com.je.common.base.service.CommonService;
import com.je.common.base.service.MetaResourceService;
import com.je.common.base.service.MetaService;
import com.je.common.base.service.rpc.BeanService;
import com.je.common.base.service.rpc.SystemVariableRpcService;
import com.je.common.base.util.ArrayUtils;
import com.je.common.base.util.DateUtils;
import com.je.common.base.util.StringUtil;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import com.je.meta.model.ExcelParameterVo;
import com.je.meta.model.ExcelReturnVo;
import com.je.meta.service.ExcelAssistService;
import com.je.meta.service.SheetImporExceltExecutionService;
import com.je.meta.service.WayImportExcelHandleDataService;
import com.je.meta.util.commonUtils.CommonUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Pattern;

@Service
public class SheetImporExceltExecutionServiceImpl implements SheetImporExceltExecutionService {
    @Autowired
    private WayImportExcelHandleDataService wayImportExcelHandleDataService;

    @Autowired
    private CommonService commonService;

    @Autowired
    private MetaResourceService metaResourceService;

    @Autowired
    private MetaService metaService;

    @Autowired
    private ExcelAssistService excelAssistService;

    @Autowired
    private SystemVariableRpcService systemVariableRpcService;
    @Override
    public ExcelReturnVo executeDataPre(Map<String, Object> ddMap, ExcelParameterVo excelParamVo) {
        /**
         * 若有前后逻辑，会进此方法
         */
        DynaBean sheet =excelParamVo.getSheet();
        ExcelReturnVo excelReturnVo =null;
        String beforeType  =sheet.getStr("BEFORE_TYPE");
        String beforeSql =sheet.getStr("BEFORE_SQL");
        if("SQL".equals(beforeType)){
            wayImportExcelHandleDataService.handleDataBySql(beforeSql,ddMap);
        }
        if("BEAN".equals(beforeType)){
            String DATA_CLTYPE = sheet.getStr("DATA_CLTYPE");
            if("ALL".equals(DATA_CLTYPE)){
                //全部处理
                excelReturnVo =  wayImportExcelHandleDataService.handleDataByBean(sheet.getStr("BEFORE_BEAN"),sheet.getStr("BEFORE_METHOD"),excelParamVo);
            }
            /*if("ONE".equals(DATA_CLTYPE)){
                //逐条处理
                List<DynaBean> list = excelParamVo.getSheetValues();
                for(DynaBean dynaBean:list){
                    ExcelParamVo excelParamVoItem = new ExcelParamVo(excelParamVo.getRequest(),dynaBean);
                    wayImportExcelHandleDataService.handleDataByBean(sheet.getStr("BEFORE_BEAN"),sheet.getStr("BEFORE_METHOD"),null);
                }
            }*/
        }
        return excelReturnVo;
    }

    @Override
    public List<DynaBean> executeData(DynaBean group, DynaBean sheet, String groupTemId, Map<String, Object> ddMap, List<DynaBean> nowSheetData, HttpServletRequest request,Map<String,Object> result) {
       if(nowSheetData!=null&&nowSheetData.size()>0){
           //处理方式
           String type = sheet.getStr("DATA_TYPE");
           ExcelReturnVo excelReturnVo =null;
           if("BEAN".equals(type)){
               //处理策略 ：全部处理；逐条处理
               String DATA_CLTYPE = sheet.getStr("DATA_CLTYPE");
               if("ALL".equals(DATA_CLTYPE)){
                   excelReturnVo =  wayImportExcelHandleDataService.handleDataByBean(sheet.getStr("DATA_BEAN"),sheet.getStr("DATA_METHOD"),null);
                   result.put("code",excelReturnVo.getCode());
                   result.put("msg",excelReturnVo.getMsg());
                   result.put("sheet",excelReturnVo.getSheetIndex());
                   return excelReturnVo.getSheetValues();
               }
               if("ONE".equals(DATA_CLTYPE)){
                   List<Map<String,Object>> errorinfo =new ArrayList<>();
                   List<DynaBean> list = new ArrayList<>();
                   for(DynaBean excelDataItem:nowSheetData){
                       ExcelReturnVo item=   wayImportExcelHandleDataService.handleDataByBean(sheet.getStr("DATA_BEAN"),sheet.getStr("DATA_METHOD"),null);
                       if(item.getCode()==-2||item.getCode()==-3){
                           Map<String,Object> errorMap =buildResult(item);
                           errorMap.put("rowIndex",item.getRowIndex());
                           errorinfo.add(errorMap);
                       }else{
                           list.add(item.getDynaBean());
                       }
                   }
                   if(errorinfo!=null&&errorinfo.size()>0){
                       result.put("sheetOneHandleResult",errorinfo);
                       result.put("code",-2);
                   }
                   return list;
               }
           }else{
               //如果不是预处理，则保存到最终的数据表中
               if(!"1".equals(group.getStr("EXCELGROUP_PRVIEW"))){
                   saveData(sheet,nowSheetData);
               }
               return nowSheetData;
           }
       }
       return null;
    }

    @Override
    public void handleData(DynaBean group, DynaBean sheet, List<Map<Integer, Object>> excelDatas,HttpServletRequest request) {
        //构建用户信息
        Map<String, Object> ddMap = buildVariableList(request);
        //是否预处理
        String prviewData = group.getStr("EXCELGROUP_PRVIEW");
        //是否前后逻辑
        String qhlj =sheet.getStr("EXCELSHEET_QHLJ");
        //是否系统处理
        String type = sheet.getStr("DATA_TYPE");
        //将excel数据转换为DynaBean
        List<DynaBean> fields =metaResourceService.selectByTableCodeAndNativeQuery("JE_CORE_EXCELFIELD",
                NativeQuery.build().eq("JE_CORE_EXCELSHEET_ID",sheet.getStr("JE_CORE_EXCELSHEET_ID")).orderByAsc("SY_ORDERINDEX"));
        DynaBean defaultValues = new DynaBean();
        String funcCode = sheet.getStr("FUNCCODE");
        String defaultFuncVal = sheet.getStr("DATA_DEFAULTVALUE");
        if ("1".equals(defaultFuncVal)) {
            commonService.buildFuncDefaultValues(funcCode, defaultValues);
        }
        String defaultCreateInfo = sheet.getStr("DATA_CREATEINFO");
        String tableCode = sheet.getStr("TABLECODE");

        //科学计数
        List<String> kxjsFields=new ArrayList<String>();
        //日期
        List<String> dateFields=new ArrayList<String>();
        //日期时间
        List<String> dateTimeFields=new ArrayList<String>();
        //所占行 A-Z
        Map<String, DynaBean> fieldInfos = new HashMap<String, DynaBean>();
        //处理后的数据
        List<DynaBean> datas = new ArrayList<DynaBean>();
        //自动带值数据集
        Map<String, List<DynaBean>> dzValues = new HashMap<String, List<DynaBean>>();
        //带值字段集合
        List<String> dzFields = new ArrayList<String>();
        //以code为key的数据集合
        Map<String, DynaBean> fieldCodeInfos = new HashMap<String, DynaBean>();
        for(DynaBean field:fields){
            String fieldCode = field.getStr("EXCELFIELD_CODE");
            String defaultValue = field.getStr("EXCELFIELD_VALUE");
            String EXCELFIELD_COLUMN = field.getStr("EXCELFIELD_COLUMN");
            String EXCELFIELD_XTYPE = field.getStr("EXCELFIELD_XTYPE");
            fieldCodeInfos.put(field.getStr("EXCELFIELD_CODE"), field);

            if (StringUtil.isNotEmpty(EXCELFIELD_COLUMN)) {
                fieldInfos.put(EXCELFIELD_COLUMN, field);
            }
            //特殊字段类型
            if("datefield".equals(EXCELFIELD_XTYPE)){
                dateFields.add(fieldCode);
            }
            if("datetimefield".equals(EXCELFIELD_XTYPE)){
                dateTimeFields.add(fieldCode);
            }
            //带值配置
            excelAssistService.parseAllDzValues(field, ddMap, dzValues, dzFields, CommonUtils.getRequestParams(request));

            //处理默认值
            if(StringUtil.isNotEmpty(defaultValue)&&(defaultValue.startsWith("@")&&defaultValue.endsWith("@"))){
                defaultValue="{"+defaultValue+"}";
            }
            if(StringUtil.isNotEmpty(defaultValue)){
                defaultValues.set(fieldCode,defaultValue);
            }

            //去除科学计数
            if("1".equals(field.getStr("EXCELFIELD_QCKXJS"))){
                kxjsFields.add(fieldCode);
            }
            //主子
        }

        for(int j =0;j<excelDatas.size();j++){
            DynaBean dynaBean = new DynaBean();
            if ("1".equals(defaultFuncVal)) {
                dynaBean.setValues(defaultValues.clone().getValues());
            }
            if ("1".equals(defaultCreateInfo)) {
                commonService.buildModelCreateInfo(dynaBean);
            }
            if (StringUtil.isNotEmpty(tableCode)) {
                dynaBean.set(BeanService.KEY_TABLE_CODE, tableCode);
            }
            Map<Integer,Object> excelItemMap = excelDatas.get(j);
            for (Map.Entry<Integer, Object> entry : excelItemMap.entrySet()) {
                String nowName = getExcelColumnName(entry.getKey());
                if(fieldInfos.containsKey(nowName)){
                    DynaBean field = fieldInfos.get(nowName);
                    Object excelValue = entry.getValue();
                    if(!Objects.isNull(excelValue) && !Strings.isNullOrEmpty(excelValue.toString())){
                        dynaBean.set(field.getStr("EXCELFIELD_CODE"),excelValue);
                    }
                }
            }
            //处理带值
            for (String dzField : dzFields) {
                DynaBean fieldInfo = fieldCodeInfos.get(dzField);
                excelAssistService.doSetBeanDzValue(fieldInfo, dynaBean, dzValues, ddMap);
            }
            //处理科学计数
            for(String kejs:kxjsFields){
                String val = dynaBean.getStr(kejs);
                if (StringUtil.isNotEmpty(val)) {
                    String regx = "^((-?\\d+.?\\d*)[Ee]{1}(-?\\d+))$";
                    Pattern pattern = Pattern.compile(regx);
                    if (pattern.matcher(val).matches()) {
                        BigDecimal b = new BigDecimal(val);
                        val = b.toPlainString();
                    }
                }
                dynaBean.set(kejs, val);
            }
            //处理日期
            for (String dateField : dateFields) {
                String dateValue = dynaBean.getStr(dateField);
                if (!Strings.isNullOrEmpty(dateValue)) {
                    try {
                        dynaBean.setStr(dateField, DateUtils.formatDate(DateUtils.getDate(dateValue)));
                    } catch (Exception e) {
                        throw new RuntimeException("日期格式错误");
                    }
                }
            }
            //处理日期时间
            for (String dateTimeField : dateTimeFields) {
                String dateValue = dynaBean.getStr(dateTimeField);
                if (!Strings.isNullOrEmpty(dateValue)) {
                    try {
                        dynaBean.setStr(dateTimeField, DateUtils.formatDateTime(DateUtils.getDate(dateValue)));
                    } catch (Exception e) {
                        throw new RuntimeException("日期格式错误");
                    }
                }
            }
            dynaBean.set("__CODE__", "1");
            dynaBean.set("__MSG__", "正确");
            datas.add(dynaBean);
        }
        //前
        if("1".equals(qhlj)){
           ExcelReturnVo excelReturnVo = executeDataPre(ddMap,new ExcelParameterVo("SHEET_BEFORE",group,sheet,datas,request));
           if("BEAN".equals(sheet.getStr("BEFORE_TYPE"))){
               datas=excelReturnVo.getSheetValues();
           }
        }
        if("BEAN".equals(type)){ //处理 -- 自定义处理
            //处理策略 ：全部处理；逐条处理
            String DATA_CLTYPE = sheet.getStr("DATA_CLTYPE");
            if("ALL".equals(DATA_CLTYPE)){
                ExcelReturnVo excelReturnVo =  wayImportExcelHandleDataService.handleDataByBean(sheet.getStr("DATA_BEAN"),sheet.getStr("DATA_METHOD"),new ExcelParameterVo("SHEET_DATA_ALL",group,sheet,datas));
                datas = excelReturnVo.getSheetValues();
            }
            /*if("ONE".equals(DATA_CLTYPE)){

            }*/
        }else if(!"1".equals(prviewData)){//处理 -- 系统处理
            //将数据存入目标表
            saveData(sheet,datas);
        }

        if("1".equals(prviewData)){
            //预处理将数据存入临时表
            excelAssistService.temporarySaveData(group,  sheet, datas,  fields,  group.getStr("groupTemId"));
        }
        //后
        if("1".equals(qhlj)){
            executeDataAfter(ddMap,new ExcelParameterVo("SHEET_AFTER",group,sheet,null,request));
        }

    }

    private Map<String, Object> buildVariableList(HttpServletRequest request) {
        Map<String, Object> ddMap = systemVariableRpcService.formatCurrentUserAndCachedVariables();
        ddMap.putAll(getRequestParams(request));
        return  ddMap;
    }

    private Map<String, String> getRequestParams(HttpServletRequest request) {
        Enumeration ener = request.getParameterNames();
        Map<String, String> params = new HashMap<String, String>();
        while (ener.hasMoreElements()) {
            String key = ener.nextElement() + "";
            params.put(key, request.getParameter(key));
        }
        return params;
    }

    private String getExcelColumnName(int i) {
        StringBuilder str = new StringBuilder(2);
        setExcelColumnName(str, i);
        return str.toString();
    }

    private void setExcelColumnName(StringBuilder str, int col) {
        int tmp = col / 26;
        if (tmp > 26) {
            setExcelColumnName(str, tmp - 1);
        } else if (tmp > 0) {
            str.append((char) (tmp + 64));
        }
        str.append((char) (col % 26 + 65));
    }

    @Override
    public void saveData(DynaBean sheet, List<DynaBean> datas) {
        //修改操作
        String DATA_UPDATE = sheet.getStr("DATA_UPDATE");
        String tableCode = sheet.getStr("EXCELSHEET_TABLECODE", "");
        for(DynaBean data : datas){
            if("1".equals(DATA_UPDATE)){
                List<String> unSqls = new ArrayList<>();
                String updateCodes = sheet.getStr("EXCELSHEET_WYZDBM");
                if (StringUtil.isNotEmpty(updateCodes)) {
                    for (String fieldCode : updateCodes.split(",")) {
                        unSqls.add(" " + fieldCode + "='" + data.getStr(fieldCode) + "'");
                    }
                    List<DynaBean> dbLists = metaService.select(tableCode, ConditionsWrapper.builder().apply(" AND " + StringUtil.buildSplitString(ArrayUtils.getArray(unSqls), " AND ")));
                    if(dbLists!=null&&dbLists.size()>0){
                        data.set(data.getStr(BeanService.KEY_PK_CODE), dbLists.get(0).getStr(data.getStr(BeanService.KEY_PK_CODE)));
                        commonService.buildModelModifyInfo(data);
                        metaService.update(data);
                    }
                }
            }else {
                metaService.insert(data);
            }
        }
    }


    @Override
    public ExcelReturnVo executeDataAfter(Map<String, Object> ddMap, ExcelParameterVo excelParamVo) {
        /**
         * 若有前后逻辑，会进此方法
         */

        return null;
    }
}
